package com.insight.common.system.util;

import cn.hutool.core.util.RandomUtil;
import com.yuanqiao.insight.common.util.common.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.poi.ss.usermodel.Workbook;
import org.jeecg.common.util.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;
import java.util.List;

/**
 * @author wangruheng
 * @title: ZipEncryUtils
 * @projectName jeecg-boot-parent
 * @description: TODO 导出加密
 * @date 2021/8/11-9:02
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "jeecg.path.upload")
public class ZipEncryUtilsJeecg {
    @Value("${jeecg.path.upload}")
    private String upload;

    /**
     * Excel 导出加密方法
     *
     * @param fileName 文件名称
     * @param response response
     * @param workbook Excel导出对象
     * @param passwd   加密密码
     * @throws Exception
     */
    public void excelEncry(String fileName, HttpServletResponse response, Workbook workbook, String passwd) throws ZipException, IOException {
        String[] split = fileName.split("\\.");
        fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];

        ZipParameters parameters = getZipParameters(fileName, passwd);
        String zipFileName = fileName.substring(0, fileName.lastIndexOf('.')) + ".zip";
        String tempStr1 = DateUtils.formatDateHMS(new Date()).replaceAll(":", "");

        // 保留三天内数据（含今天）
        List<String> dayStrList = TimeUtils.getDaysBetween(
                TimeUtils.getBeforeDateStr(tempStr1.split(" ")[0], -2), tempStr1.split(" ")[0]);

        File directory = new File(upload + "/zipEncry");
        File[] directoryFiles = directory.listFiles();
        if (directoryFiles != null && directoryFiles.length > 0) {
            for (File dirFile : directoryFiles) {
                String directoryFilePath = dirFile.getPath();
                String lastPathStr = directoryFilePath.substring(directoryFilePath.lastIndexOf("\\") + 1);
                if (!dayStrList.contains(lastPathStr)) {
                    deleteFolders(directoryFilePath);
                }
            }
        }

        String directoryPath = upload + "/zipEncry/" + tempStr1.split(" ")[0] + "/";
        File directory1 = new File(directoryPath);
        if (!directory1.isDirectory()) {
            directory1.mkdirs();
        }

        String zipFileUrl = directoryPath + zipFileName;
        log.info("zipFileUrl : ================ " + zipFileUrl);

        byte[] bytes;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            workbook.write(bos);
            bytes = bos.toByteArray();
        }

        new ZipFile(zipFileUrl).addStream(new ByteArrayInputStream(bytes), parameters);

        File file = new File(zipFileUrl);
        // 设置响应头，告诉浏览器下载文件类型和名称
        response.setHeader("content-Type", "multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
        response.setCharacterEncoding("UTF-8");

        try (InputStream fis = Files.newInputStream(file.toPath()); OutputStream os = response.getOutputStream()) {
            byte[] b = new byte[1024 * 1024 * 20];
            int len;
            while ((len = fis.read(b)) > 0) {
                os.write(b, 0, len);
            }
            os.flush();
        }
    }

    /**
     * 导出 Excel 模板（带加密）
     *
     * @param fileName 文件名
     * @param response HTTP 响应
     * @param inputStream 模板流（外部负责关闭）
     * @param passwd 加密密码
     */
    public void excelTemplate(String fileName, HttpServletResponse response, InputStream inputStream, String passwd) throws ZipException, IOException {
        ZipParameters parameters = getZipParameters(fileName, passwd);
        String zipFileName = fileName.substring(0, fileName.lastIndexOf('.')) + ".zip";
        String zipFileUrl = getPoth() + zipFileName;

        new ZipFile(zipFileUrl).addStream(inputStream, parameters);

        File file = new File(zipFileUrl);
        // 设置响应头
        response.setHeader("content-Type", "multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
        response.setCharacterEncoding("UTF-8");

        try (InputStream fis = Files.newInputStream(file.toPath()); OutputStream os = response.getOutputStream()) {
            byte[] b = new byte[1024 * 1024 * 20];
            int len;
            while ((len = fis.read(b)) > 0) {
                os.write(b, 0, len);
            }
            os.flush();
        }
    }

    /**
     * PDF 文件加密打包为 zip
     *
     * @param pdfPath PDF 文件路径
     * @param passwd 压缩密码
     * @return 加密后的 zip 文件路径
     */
    public String pdfEncry(String pdfPath, String passwd) throws FileNotFoundException, ZipException {
        pdfPath = pdfPath.replaceAll("//", "/").replaceAll("\\\\", "/");
        String pdfName = pdfPath.substring(pdfPath.lastIndexOf('/') + 1);

        ZipParameters parameters = getZipParameters(pdfName, passwd);
        String zipFileUrl = getPoth() + pdfName.substring(0, pdfName.lastIndexOf('.')) + ".zip";

        try (InputStream inputStream = new FileInputStream(new File(pdfPath))) {
            new ZipFile(zipFileUrl).addStream(inputStream, parameters);
        }

        return zipFileUrl;
    }

    /**
     * 获取压缩参数
     *
     * @param fileName 文件名
     * @param passwd 密码
     * @return ZipParameters 对象
     */
    private ZipParameters getZipParameters(String fileName, String passwd) {
        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        parameters.setSourceExternalStream(true);
        parameters.setFileNameInZip(fileName);
        if (!"".equals(passwd)) {
            parameters.setEncryptFiles(true);
            parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
            parameters.setPassword(passwd.toCharArray());
        }
        return parameters;
    }

    /**
     * 获取 zip 存放目录
     * @return 存储路径
     */
    private String getPoth() {
        String filePath = upload + "/zipEncry/";
        File file = new File(filePath);
        if (!file.isDirectory()) {
            file.mkdirs();
        }
        return filePath;
    }

    /**
     * 递归删除文件夹及内容
     *
     * @param filePath 要删除的路径
     */
    public static void deleteFolders(String filePath) {
        Path path = Paths.get(filePath);
        try {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
                    Files.delete(file);
                    System.out.println("删除文件: " + file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir,
                                                          IOException exc) throws IOException {
                    Files.delete(dir);
                    System.out.println("删除文件夹: " + dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
